package co.gov.medellin.ssti.sub.model.dao.impl;

import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Repository;

import co.gov.medellin.ssti.sub.common.util.FiltrosReportesUtil;
import co.gov.medellin.ssti.sub.model.dao.EmpresaDAO;
import co.gov.medellin.ssti.sub.model.dao.exception.DAOException;
import co.gov.medellin.ssti.sub.model.service.ReporteTotalComunaService;
import co.gov.medellin.ssti.sub.model.service.VflexService;
import co.gov.medellin.ssti.sub.model.vo.BeneficioOtorgadoEmpresaVO;
import co.gov.medellin.ssti.sub.model.vo.BeneficioOtorgadoVO;
import co.gov.medellin.ssti.sub.model.vo.BeneficioVO;
import co.gov.medellin.ssti.sub.model.vo.CondicionConsultaVO;
import co.gov.medellin.ssti.sub.model.vo.EmpresaVO;
import co.gov.medellin.ssti.sub.model.vo.ProgramaVO;
import co.gov.medellin.ssti.sub.model.vo.RepAtributoVO;
import co.gov.medellin.ssti.sub.model.vo.RepEmpresaVO;
import co.gov.medellin.ssti.sub.model.vo.ReportComunaVO;
import co.gov.medellin.ssti.sub.model.vo.ReporteDetVO;
import co.gov.medellin.ssti.sub.model.vo.ReporteTotalComunaVO;
import co.gov.medellin.ssti.sub.model.vo.SubprogramaVO;
import co.gov.medellin.ssti.sub.model.vo.VflexVO;

@Repository
public class EmpresaDAOImpl extends NamedParameterJdbcDaoSupport implements
		EmpresaDAO {
	@Autowired
	VflexService vflexServiceImpl;

	private static final String FIND_ULTIMOS_BENEFICIOS = "SELECT bo.*, ("
			+ " SELECT SUM(valor_beneficio) FROM TCS_BOT_EMPRESA inbot "
			+ " WHERE inbot.EMP_CODIGO = bo.CODEMP AND bo.CODEMP = :CODEMP "
			+ " AND inbot.SBPR_CODIGO = bo.CODSUBPROG ) valorben "
			+ " FROM VCS_BOT_EMPRESA bo WHERE CODBOT IN ( "
			+ " SELECT MAX(bot.CODIGO) codigo FROM TCS_BOT_EMPRESA bot "
			+ " GROUP BY bot.SBPR_CODIGO " + " ) AND bo.CODEMP = :CODEMP";

	public Collection<EmpresaVO> findEmpresaByCriteria(EmpresaVO criteria) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		StringBuffer query = new StringBuffer(
				"SELECT emp.CODIGO, emp.TIPO_DOCUMENTO, emp.NIT_IDUPA, emp.ID_BIOMETRICO, "
						+ " emp.NOMBRE_UPA, emp.RAZON_SOCIAL, emp.NOM_REP_LEGAL , emp.DOC_REP_LEGAL, "
						+ " emp.VFL_CODIGO_COMUNA, emp.VFL_CODIGO_BARRIO, emp.VFL_CODIGO_ZONA, "
						+ " emp.NOMBRE_CONTACTO, emp.DIRECCION, emp.TELEFONO, "
						+ " emp.SECTOR, emp.SUBSECTOR, emp.NUMERO_COMODATO, "
						+ " emp.EMAIL, emp.OBSERVACIONES, "
						+ " vfc.NOMBRE STRCOMUNA, vfb.NOMBRE STRBARRIO, vfz.NOMBRE STRZONA "
						+ " FROM TCS_EMPRESA emp "
						+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE vfc ON emp.VFL_CODIGO_COMUNA = vfc.CODIGO "
						+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE vfb ON emp.VFL_CODIGO_BARRIO = vfb.CODIGO "
						+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE vfz ON emp.VFL_CODIGO_ZONA = vfz.CODIGO "
						+ " WHERE 1=1 ");
		if (criteria.getTipoDocumento() != null
				&& !criteria.getTipoDocumento().isEmpty()) {
			query.append(" AND UPPER(EMP.TIPO_DOCUMENTO) = UPPER(:TIPO_DOCUMENTO) ");
			namedParameters.put("TIPO_DOCUMENTO", criteria.getTipoDocumento()
					.toUpperCase());
		}
		if (criteria.getNitIdupa() != null
				&& !criteria.getNitIdupa().equals("")) {
			query.append(" AND UPPER(EMP.NIT_IDUPA) LIKE UPPER(:NIT_IDUPA) ");
			namedParameters.put("NIT_IDUPA", "%"
					+ criteria.getNitIdupa().toUpperCase() + "%");
		}
		if (criteria.getRazonSocial() != null
				&& !criteria.getRazonSocial().equals("")) {
			query.append(" AND UPPER(EMP.RAZON_SOCIAL) LIKE UPPER(:RAZON_SOCIAL) ");
			namedParameters.put("RAZON_SOCIAL", "%"
					+ criteria.getRazonSocial().toUpperCase() + "%");
		}
		query.append(" ORDER BY emp.RAZON_SOCIAL ");
		// System.out.println("query: " + query.toString());
		// for (String str : namedParameters.keySet()) {
		// System.out.println(str + ":" + namedParameters.get(str));
		// }
		List<EmpresaVO> empresas = getNamedParameterJdbcTemplate().query(
				query.toString(), namedParameters, new EmpresaVORowMapper());
		return empresas;
	}

	public EmpresaVO findEmpresaByCodigo(long codigo) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		StringBuffer query = new StringBuffer(
				"SELECT emp.CODIGO, emp.TIPO_DOCUMENTO, emp.NIT_IDUPA, emp.ID_BIOMETRICO, "
						+ " emp.NOMBRE_UPA, emp.RAZON_SOCIAL, emp.NOM_REP_LEGAL, "
						+ " emp.DOC_REP_LEGAL, "
						+ " emp.VFL_CODIGO_COMUNA, emp.VFL_CODIGO_BARRIO, emp.VFL_CODIGO_ZONA, "
						+ " emp.NOMBRE_CONTACTO, emp.DIRECCION, emp.TELEFONO, "
						+ " emp.SECTOR, emp.SUBSECTOR, emp.NUMERO_COMODATO, emp.EMAIL, emp.OBSERVACIONES, "
						+ " vfc.NOMBRE strcomuna, vfb.NOMBRE strbarrio, vfz.NOMBRE strzona "
						+ " FROM TCS_EMPRESA emp "
						+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE vfc ON emp.VFL_CODIGO_COMUNA = vfc.CODIGO "
						+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE vfb ON emp.VFL_CODIGO_BARRIO = vfc.CODIGO "
						+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE vfz ON emp.VFL_CODIGO_ZONA = vfz.CODIGO "
						+ " WHERE emp.CODIGO = :CODIGO ");
		namedParameters.put("CODIGO", codigo);

		EmpresaVO empresa = getNamedParameterJdbcTemplate().queryForObject(
				query.toString(), namedParameters, new EmpresaVORowMapper());
		return empresa;
	}

	public int actualizarEmpresa(EmpresaVO empresa) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		String query = " UPDATE TCS_EMPRESA "
				+ " SET TIPO_DOCUMENTO = :TIPO_DOCUMENTO, NIT_IDUPA = UPPER(:NIT_IDUPA), "
				+ " ID_BIOMETRICO = :ID_BIOMETRICO, NOMBRE_UPA = UPPER(:NOMBRE_UPA), "
				+ " RAZON_SOCIAL = UPPER(:RAZON_SOCIAL), "
				+ " NOM_REP_LEGAL = UPPER(:NOM_REP_LEGAL), DOC_REP_LEGAL = :DOC_REP_LEGAL, "
				+ " VFL_CODIGO_COMUNA = :VFL_CODIGO_COMUNA, VFL_CODIGO_BARRIO = :VFL_CODIGO_BARRIO, "
				+ " VFL_CODIGO_ZONA = :VFL_CODIGO_ZONA, "
				+ " NOMBRE_CONTACTO = :NOMBRE_CONTACTO, DIRECCION = :DIRECCION, TELEFONO = :TELEFONO, "
				+ " SECTOR = :SECTOR, SUBSECTOR = :SUBSECTOR, NUMERO_COMODATO = :NUMERO_COMODATO, "
				+ " EMAIL = :EMAIL, OBSERVACIONES = :OBSERVACIONES "
				+ " WHERE CODIGO = :CODIGO ";

		namedParameters.put("CODIGO", empresa.getCodigo());
		namedParameters.put("TIPO_DOCUMENTO", empresa.getTipoDocumento());
		namedParameters.put("NIT_IDUPA", empresa.getNitIdupa());
		namedParameters.put("ID_BIOMETRICO", empresa.getIdBiometrico());
		namedParameters.put("NOMBRE_UPA", empresa.getNombreUpa());
		namedParameters.put("RAZON_SOCIAL", empresa.getRazonSocial());
		namedParameters.put("NOM_REP_LEGAL", empresa.getNomRepLegal());
		namedParameters.put("DOC_REP_LEGAL", empresa.getDocRepLegal());
		namedParameters.put("VFL_CODIGO_COMUNA", empresa.getVflCodigoComuna());
		namedParameters.put("VFL_CODIGO_BARRIO", empresa.getVflCodigoBarrio());
		namedParameters.put("VFL_CODIGO_ZONA", empresa.getVflCodigoZona());
		namedParameters.put("NOMBRE_CONTACTO", empresa.getNombreContacto());
		namedParameters.put("DIRECCION", empresa.getDireccion());
		namedParameters.put("TELEFONO", empresa.getTelefono());
		namedParameters.put("SECTOR", empresa.getSector());
		namedParameters.put("SUBSECTOR", empresa.getSubSector());
		namedParameters.put("NUMERO_COMODATO", empresa.getNumeroComodato());
		namedParameters.put("EMAIL", empresa.getEmail());
		namedParameters.put("OBSERVACIONES", empresa.getObservaciones());

		return getNamedParameterJdbcTemplate().update(query, namedParameters);
	}

	public int ingresarEmpresa(EmpresaVO empresa) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		StringBuffer query = new StringBuffer(
				" INSERT INTO TCS_EMPRESA "
						+ " (CODIGO, TIPO_DOCUMENTO, NIT_IDUPA, ID_BIOMETRICO, NOMBRE_UPA, "
						+ " RAZON_SOCIAL, NOM_REP_LEGAL, DOC_REP_LEGAL, "
						+ " VFL_CODIGO_COMUNA, VFL_CODIGO_BARRIO, VFL_CODIGO_ZONA, "
						+ " NOMBRE_CONTACTO, DIRECCION, TELEFONO,  SECTOR, SUBSECTOR, "
						+ " NUMERO_COMODATO, EMAIL, OBSERVACIONES ) "
						+ " VALUES (SCS_EMP.NEXTVAL, :TIPO_DOCUMENTO, UPPER(:NIT_IDUPA), :ID_BIOMETRICO, UPPER(:NOMBRE_UPA), "
						+ " UPPER(:RAZON_SOCIAL), UPPER(:NOM_REP_LEGAL), :DOC_REP_LEGAL, "
						+ " :VFL_CODIGO_COMUNA, :VFL_CODIGO_BARRIO, :VFL_CODIGO_ZONA, "
						+ " UPPER(:NOMBRE_CONTACTO), UPPER(:DIRECCION), :TELEFONO, UPPER(:SECTOR), UPPER(:SUBSECTOR), "
						+ " :NUMERO_COMODATO, :EMAIL, :OBSERVACIONES ) ");

		namedParameters.put("TIPO_DOCUMENTO", empresa.getTipoDocumento());
		namedParameters.put("NIT_IDUPA", empresa.getNitIdupa());
		namedParameters.put("ID_BIOMETRICO", empresa.getIdBiometrico());
		namedParameters.put("NOMBRE_UPA", empresa.getNombreUpa());
		namedParameters.put("RAZON_SOCIAL", empresa.getRazonSocial());
		namedParameters.put("NOM_REP_LEGAL", empresa.getNomRepLegal());
		namedParameters.put("DOC_REP_LEGAL", empresa.getDocRepLegal());
		namedParameters.put("VFL_CODIGO_COMUNA", empresa.getVflCodigoComuna());
		namedParameters.put("VFL_CODIGO_BARRIO", empresa.getVflCodigoBarrio());
		namedParameters.put("VFL_CODIGO_ZONA", empresa.getVflCodigoZona());
		namedParameters.put("NOMBRE_CONTACTO", empresa.getNombreContacto());
		namedParameters.put("DIRECCION", empresa.getDireccion());
		namedParameters.put("TELEFONO", empresa.getTelefono());
		namedParameters.put("SECTOR", empresa.getSector());
		namedParameters.put("SUBSECTOR", empresa.getSubSector());
		namedParameters.put("NUMERO_COMODATO", empresa.getNumeroComodato());
		namedParameters.put("EMAIL", empresa.getEmail());
		namedParameters.put("OBSERVACIONES", empresa.getObservaciones());

		return getNamedParameterJdbcTemplate().update(query.toString(),
				namedParameters);
	}

	public Collection<BeneficioOtorgadoVO> findBeneficios(EmpresaVO criteria) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		StringBuffer query = new StringBuffer(" SELECT bot.*, "
				+ " area.NOMBRE area_nombre, "
				+ " prog.NOMBRE programa_nombre, "
				+ " subprog.NOMBRE subprograma_nombre, "
				+ " sede.NOMBRE sede_nombre " + " FROM TCS_EMPRESA emp "
				+ " INNER JOIN TCS_BOT_EMPRESA bot "
				+ " ON emp.CODIGO = bot.EMP_CODIGO "
				+ " INNER JOIN TCS_BEN_SUBPROGRAMA subprog "
				+ " ON bot.sbpr_codigo = subprog.codigo "
				+ " INNER JOIN TCS_BEN_PROGRAMA prog "
				+ " ON subprog.prg_codigo = prog.codigo "
				+ " INNER JOIN TCS_BEN_AREA area "
				+ " ON area.codigo = prog.area_codigo "
				+ " INNER JOIN TCS_BEN_SEDE sede "
				+ " ON sede.codigo = bot.sede_codigo "
				+ " WHERE emp.codigo = :CODIGO AND area.area_codigo IS NULL ");

		namedParameters.put("CODIGO", criteria.getCodigo());

		// TODO: Debe ser consulta agrupada (total x subprograma)?

		List<BeneficioOtorgadoVO> beneficios = getNamedParameterJdbcTemplate()
				.query(query.toString(), namedParameters,
						new RowMapper<BeneficioOtorgadoVO>() {

							public BeneficioOtorgadoVO mapRow(ResultSet rs,
									int rowNum) throws SQLException {
								BeneficioOtorgadoVO vo = new BeneficioOtorgadoVO();
								vo.setCodigo(rs.getLong("CODIGO"));
								vo.setSbprCodigo(rs.getLong("SBPR_CODIGO"));
								vo.setBenCodigo(rs.getLong("BEN_CODIGO"));
								vo.setSedeCodigo(rs.getLong("SEDE_CODIGO"));
								vo.setTercero(rs.getString("TERCERO"));
								vo.setFechaBeneficio(rs
										.getString("FECHA_BENEFICIO"));
								vo.setUsuarioCrea(rs.getString("USUARIO_CREA"));
								vo.setFechaCrea(rs.getString("FECHA_CREA"));
								vo.setTerminalCrea(rs
										.getString("TERMINAL_CREA"));
								vo.setUsuarioModifica(rs
										.getString("USUARIO_MODIFICA"));
								vo.setFechaModifica(rs
										.getString("FECHA_MODIFICA"));
								vo.setTerminalModifica(rs
										.getString("TERMINAL_MODIFICA"));
								vo.setCampoA1(rs.getString("CAMPO_A1"));
								vo.setDesplazado(rs.getString("DESPLAZADO"));
								vo.setCampoA3(rs.getString("CAMPO_A3"));
								vo.setTipoBeneficio(rs
										.getString("TIPO_BENEFICIO"));
								vo.setCampoA5(rs.getString("CAMPO_A5"));
								vo.setCampoA6(rs.getString("CAMPO_A6"));
								vo.setCampoN1(rs.getLong("CAMPO_N1"));
								vo.setCampoN2(rs.getLong("CAMPO_N2"));
								vo.setCampoN3(rs.getLong("CAMPO_N3"));
								vo.setCampoF1(rs.getString("CAMPO_F1"));
								vo.setCampoF2(rs.getString("CAMPO_F2"));
								vo.setCampoF3(rs.getString("CAMPO_F3"));
								vo.setValorBeneficio(rs
										.getLong("VALOR_BENEFICIO"));

								// adicionales
								vo.setNombreArea(rs.getString("area_nombre"));
								vo.setNombrePrograma(rs
										.getString("programa_nombre"));
								vo.setNombreSubprograma(rs
										.getString("subprograma_nombre"));
								vo.setNombreSede(rs.getString("sede_nombre"));
								return vo;
							}
						});
		return beneficios;
	}

	public Collection<BeneficioOtorgadoEmpresaVO> findUltimosBeneficios(
			Long codigoEmpresa) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		namedParameters.put("CODEMP", codigoEmpresa);
		System.out.println(FIND_ULTIMOS_BENEFICIOS);
		System.out.println("CODEMP: " + codigoEmpresa);
		List<BeneficioOtorgadoEmpresaVO> beneficios = getNamedParameterJdbcTemplate()
				.query(FIND_ULTIMOS_BENEFICIOS, namedParameters,
						new RowMapper<BeneficioOtorgadoEmpresaVO>() {

							public BeneficioOtorgadoEmpresaVO mapRow(
									ResultSet rs, int rowNum)
									throws SQLException {
								BeneficioOtorgadoEmpresaVO vo = new BeneficioOtorgadoEmpresaVO();
								vo.setCodigo(rs.getLong("CODBOT"));
								vo.setSbprCodigo(rs.getLong("CODSUBPROG"));
								vo.setEmpCodigo(rs.getLong("CODEMP"));
								vo.setSedeCodigo(rs.getLong("CODSEDE"));
								vo.setFechaMedicion(rs
										.getString("FECHA_MEDICION"));
								vo.setUsuarioCrea(rs.getString("USUARIOCREA"));
								vo.setRenovar(rs.getString("RENOVAR"));
								vo.setValorBeneficio(rs.getLong("VALORBEN"));

								// adicionales
								vo.setNombreArea(rs.getString("NOMAREA"));
								vo.setNombrePrograma(rs.getString("NOMPROG"));
								vo.setNombreSubprograma(rs
										.getString("NOMSUBPROG"));
								vo.setNombreSede(rs.getString("NOMSEDE"));
								return vo;
							}
						});
		return beneficios;
	}

	public Collection<BeneficioVO> findDetalleBeneficios(Long codigoBeneficio,
			Long codigoEmpresa) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		String query = "SELECT * FROM VCS_BOT_EMPRESA "
				+ " WHERE CODEMP = :CODEMP AND CODSUBPROG = :CODSUBPROG ORDER BY CODBOT";
		namedParameters.put("CODEMP", codigoEmpresa);
		namedParameters.put("CODSUBPROG", codigoBeneficio);

		Collection<BeneficioVO> detalles = new ArrayList<BeneficioVO>();

		List<Map<String, Object>> rows = getNamedParameterJdbcTemplate()
				.queryForList(query, namedParameters);
		int total = 0;
		for (Map<String, Object> row : rows) {
			BeneficioVO beneficioVO = new BeneficioVO();
			BigDecimal codSubprog = (BigDecimal) row.get("CODSUBPROG");
			BigDecimal codSede = (BigDecimal) row.get("CODSEDE");
			BigDecimal codBot = (BigDecimal) row.get("CODBOT");
			BigDecimal valor = (BigDecimal) row.get("VALOR");

			if (codSubprog != null) {
				beneficioVO.setCode(codSubprog.longValueExact());
			}

			beneficioVO.setNombre((String) row.get("NOMSUBPROG"));
			beneficioVO.setFecha((String) row.get("FECHA"));

			if (codSede != null) {
				beneficioVO.setCodSede(codSede.longValueExact());
			}

			beneficioVO.setNomSede((String) row.get("NOMSEDE"));

			if (codBot != null) {
				beneficioVO.setCodeBot(codBot.longValueExact());
			}

			if (valor != null) {
				beneficioVO.setValor(valor.intValueExact());
				total += valor.intValueExact();
			}

			detalles.add(beneficioVO);
		}

		if (detalles != null && !detalles.isEmpty()) {
			BeneficioVO beneficioVO = new BeneficioVO();
			beneficioVO.setCode(new Long("0"));
			beneficioVO.setNombre("TOTAL");
			beneficioVO.setFecha("");
			beneficioVO.setCodSede(new Long("0"));
			beneficioVO.setNomSede("");
			beneficioVO.setCodeBot(new Long("0"));
			beneficioVO.setValor(total);
			detalles.add(beneficioVO);
		}
		return detalles;
	}

	public Collection<BeneficioOtorgadoEmpresaVO> findReporteDetalladoBeneficios(
			RepEmpresaVO criteria, List<CondicionConsultaVO> filtros) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		StringBuffer query = new StringBuffer();
		query.append(" SELECT "
				+ " area.CODIGO area_codigo, area.NOMBRE area_nombre, "
				+ " subarea.CODIGO subarea_codigo, subarea.NOMBRE subarea_nombre, "
				+ " sede.CODIGO sede_codigo, sede.NOMBRE sede_nombre, "
				+ " prog.CODIGO programa_codigo, prog.NOMBRE programa_nombre, "
				+ " subp.CODIGO subprograma_codigo, subp.NOMBRE subprograma_nombre, "
				+ " emp.RAZON_SOCIAL empresa_razon_social, "
				+ " bvflex.codigo barrio_codigo, bvflex.nombre barrio_nombre, "
				+ " cvflex.codigo comuna_codigo, cvflex.nombre comuna_nombre, "
				+ " zvflex.codigo zona_codigo, zvflex.nombre zona_nombre, "
				+ " emp.NIT_IDUPA empresa_nit, "
				+ " emp.DIRECCION empresa_direccion, emp.TELEFONO empresa_telefono, "
				+ " emp.NOM_REP_LEGAL empresa_nom_rep_legal, emp.DOC_REP_LEGAL empresa_doc_rep_legal, "
				+ " bot.fecha_beneficio, bot.tercero, bot.tipo_beneficio, bot.valor_beneficio "
				+ " FROM TCS_BOT_EMPRESA bot "
				+ " JOIN TCS_EMPRESA emp ON bot.emp_codigo = emp.codigo "
				+ " JOIN TCS_BEN_SEDE sede ON sede.codigo = bot.sede_codigo "
				+ " JOIN TCS_BEN_SUBPROGRAMA subp "
				+ " ON subp.codigo = bot.sbpr_codigo "
				+ " JOIN TCS_BEN_PROGRAMA prog "
				+ " ON subp.prg_codigo = prog.codigo "
				+ " JOIN TCS_BEN_AREA subarea "
				+ " ON subp.area_codigo = subarea.codigo "
				+ " JOIN TCS_BEN_AREA area "
				+ " ON subarea.area_codigo = area.codigo "
				+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE cvflex "
				+ " ON cvflex.codigo = emp.vfl_codigo_comuna "
				+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE bvflex "
				+ " ON bvflex.codigo = emp.vfl_codigo_barrio "
				+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE zvflex "
				+ " ON zvflex.codigo = emp.vfl_codigo_zona " + " WHERE 1 = 1 ");

		if (criteria.getCodeEmpresaStr() != null
				&& !criteria.getCodeEmpresaStr().equals("")) {
			namedParameters.put("CODIGO_EMPRESA", criteria.getCodeEmpresaStr());
			query.append(" AND emp.codigo = :CODIGO_EMPRESA ");
		}
		if (criteria.getCodeProgramaStr() != null
				&& !criteria.getCodeProgramaStr().equals("")) {
			namedParameters.put("CODIGO_PROGRAMA",
					criteria.getCodeProgramaStr());
			query.append(" AND prog.codigo = :CODIGO_PROGRAMA ");
		}
		if (criteria.getCodeSedeStr() != null
				&& !criteria.getCodeSedeStr().equals("")) {
			namedParameters.put("CODIGO_SEDE", criteria.getCodeSedeStr());
			query.append(" AND sede.codigo = :CODIGO_SEDE ");
		}
		if (criteria.getCodeSubprogramaStr() != null
				&& !criteria.getCodeSubprogramaStr().equals("")) {
			namedParameters.put("CODIGO_SUBPROGRAMA",
					criteria.getCodeSubprogramaStr());
			query.append(" AND subp.codigo = :CODIGO_SUBPROGRAMA ");
		}
		if (criteria.getDesde() != null && !criteria.getDesde().equals("")) {
			namedParameters.put("DESDE", criteria.getDesde());
			query.append(" AND bot.fecha_beneficio >= :DESDE ");
		}
		if (criteria.getHasta() != null && !criteria.getHasta().equals("")) {
			namedParameters.put("HASTA", criteria.getHasta());
			query.append(" AND bot.fecha_beneficio <= :HASTA ");
		}
		System.out.println(query.toString());
		for (Object ob : namedParameters.keySet()) {
			System.out.println(ob.toString() + ": " + namedParameters.get(ob));
		}
		Collection<BeneficioOtorgadoEmpresaVO> beneficios = new ArrayList<BeneficioOtorgadoEmpresaVO>();

		Object[] ret = buildQueryFiltros(filtros);
		String queryFiltVars = (String) ret[0];
		Map<String, Object> queryFiltParams = (Map<String, Object>) ret[1];
		String sbQueryFiltVars = (String) ret[2];
		Map<String, Object> sbQueryFiltParams = (Map<String, Object>) ret[3];
		namedParameters.putAll(sbQueryFiltParams);
		System.out.println("queryFiltVars: " + queryFiltVars);
		System.out.println("queryFiltParams: " + queryFiltParams);
		System.out.println("sbQueryFiltParams: " + sbQueryFiltParams);
		System.out.println("sbQFV: " + sbQueryFiltVars);
		System.out.println("filtros: " + filtros);

		query.append(queryFiltVars);

		final Long beneficiosTotal;

		beneficios = getNamedParameterJdbcTemplate().query(query.toString(),
				namedParameters, new RowMapper<BeneficioOtorgadoEmpresaVO>() {

					public BeneficioOtorgadoEmpresaVO mapRow(ResultSet rs,
							int rowNum) throws SQLException {
						BeneficioOtorgadoEmpresaVO vo = new BeneficioOtorgadoEmpresaVO();
						vo.setAreaCodigo(rs.getLong("AREA_CODIGO"));
						vo.setNombreArea(rs.getString("AREA_NOMBRE"));
						vo.setSubareaCodigo(rs.getLong("SUBAREA_CODIGO"));
						vo.setNombreSubarea(rs.getString("SUBAREA_NOMBRE"));
						vo.setSedeCodigo(rs.getLong("SEDE_CODIGO"));
						vo.setNombreSede(rs.getString("SEDE_NOMBRE"));
						vo.setProgramaCodigo(rs.getLong("PROGRAMA_CODIGO"));
						vo.setNombrePrograma(rs.getString("PROGRAMA_NOMBRE"));
						vo.setSbprCodigo(rs.getLong("SUBPROGRAMA_CODIGO"));
						vo.setNombreSubprograma(rs
								.getString("SUBPROGRAMA_NOMBRE"));
						vo.getEmpresaVO().setRazonSocial(
								rs.getString("EMPRESA_RAZON_SOCIAL"));
						vo.getEmpresaVO().setVflCodigoBarrio(
								rs.getLong("BARRIO_CODIGO"));
						vo.getEmpresaVO().setVflCodigoComuna(
								rs.getLong("COMUNA_CODIGO"));
						vo.getEmpresaVO().setVflCodigoZona(
								rs.getLong("ZONA_CODIGO"));
						vo.setNombreBarrio(rs.getString("BARRIO_NOMBRE"));
						vo.setNombreComuna(rs.getString("COMUNA_NOMBRE"));
						vo.setNombreZona(rs.getString("ZONA_NOMBRE"));
						vo.getEmpresaVO().setNitIdupa(
								rs.getString("EMPRESA_NIT_IDUPA"));

						vo.getEmpresaVO().setDireccion(
								rs.getString("EMPRESA_DIRECCION"));
						vo.getEmpresaVO().setTelefono(
								rs.getString("EMPRESA_TELEFONO"));
						vo.getEmpresaVO().setNomRepLegal(
								rs.getString("EMPRESA_NOM_REP_LEGAL"));
						vo.getEmpresaVO().setDocRepLegal(
								rs.getString("EMPRESA_DOC_REP_LEGAL"));

						vo.setTercero(rs.getString("TERCERO"));
						vo.setFechaBeneficio(rs.getString("FECHA_BENEFICIO"));
						vo.setTipoBeneficio(rs.getString("TIPO_BENEFICIO"));
						vo.setValorBeneficio(rs.getLong("VALOR_BENEFICIO"));

						return vo;
					}
				});
		Long totalBeneficios = 0L;
		Long totalBeneficiarios = 0L;
		Iterator<BeneficioOtorgadoEmpresaVO> it = beneficios.iterator();
		while (it.hasNext()) {
			BeneficioOtorgadoEmpresaVO vo = it.next();
			totalBeneficios += vo.getValorBeneficio();
		}
		// ultima posicion - agregar fila totales.
		if (!beneficios.isEmpty()) {
			BeneficioOtorgadoEmpresaVO v = new BeneficioOtorgadoEmpresaVO();
			v.setValorBeneficio(totalBeneficios);
			beneficios.add(v);
		}
		return beneficios;
	}

	public Collection<BeneficioOtorgadoEmpresaVO> findReporteTotalBeneficios(
			RepEmpresaVO criteria, List<CondicionConsultaVO> filtros) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		StringBuffer query = new StringBuffer(
				"SELECT area.codigo area_codigo, area.nombre area_nombre, "
						+ " subarea.codigo subarea_codigo, subarea.nombre subarea_nombre, "
						+ " sede.codigo sede_codigo, sede.nombre sede_nombre, "
						+ " prog.codigo programa_codigo, prog.nombre programa_nombre, "
						+ " subp.codigo subprograma_codigo, subp.nombre subprograma_nombre, "
						+ " SUM(bot.valor_beneficio) valor_total, "
						+ " SUM(bot.presup_tot_ejecutado) presup_tot_ejecutado, "
						+ " COUNT(DISTINCT(bot.codigo)) numero_beneficios, "
						//
						+ " emp.nit_idupa, emp.razon_social "
						+ " FROM TCS_BOT_EMPRESA bot "
						+ " JOIN TCS_EMPRESA emp ON bot.emp_codigo = emp.codigo "
						+ " JOIN TCS_BEN_SEDE sede ON sede.codigo = bot.sede_codigo "
						+ " JOIN TCS_BEN_SUBPROGRAMA subp "
						+ " ON subp.codigo = bot.sbpr_codigo "
						+ " JOIN TCS_BEN_PROGRAMA prog "
						+ " ON subp.prg_codigo = prog.codigo "
						+ " JOIN TCS_BEN_AREA subarea "
						+ " ON subp.area_codigo = subarea.codigo "
						+ " JOIN TCS_BEN_AREA area "
						+ " ON prog.area_codigo = area.codigo "
						//
						+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE bvflex "
						+ " ON bvflex.codigo = emp.vfl_codigo_barrio "
						+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE cvflex "
						+ " ON cvflex.codigo = emp.vfl_codigo_comuna "
						+ " LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE zvflex "
						+ " ON zvflex.codigo = emp.vfl_codigo_zona "
						+ " WHERE 1=1 ");

		if (criteria.getCodeEmpresaStr() != null
				&& !criteria.getCodeEmpresaStr().equals("")) {
			namedParameters.put("CODIGO_EMPRESA", criteria.getCodeEmpresaStr());
			query.append(" AND emp.codigo = :CODIGO_EMPRESA ");
		}
		if (criteria.getCodeProgramaStr() != null
				&& !criteria.getCodeProgramaStr().equals("")) {
			namedParameters.put("CODIGO_PROGRAMA",
					criteria.getCodeProgramaStr());
			query.append(" AND prog.codigo = :CODIGO_PROGRAMA ");
		}
		if (criteria.getCodeSedeStr() != null
				&& !criteria.getCodeSedeStr().equals("")) {
			namedParameters.put("CODIGO_SEDE", criteria.getCodeSedeStr());
			query.append(" AND sede.codigo = :CODIGO_SEDE ");
		}
		if (criteria.getCodeSubprogramaStr() != null
				&& !criteria.getCodeSubprogramaStr().equals("")) {
			namedParameters.put("CODIGO_SUBPROGRAMA",
					criteria.getCodeSubprogramaStr());
			query.append(" AND subp.codigo = :CODIGO_SUBPROGRAMA ");
		}
		if (criteria.getDesde() != null && !criteria.getDesde().equals("")) {
			namedParameters.put("DESDE", criteria.getDesde());
			query.append(" AND bot.fecha_beneficio >= :DESDE ");
		}
		if (criteria.getHasta() != null && !criteria.getHasta().equals("")) {
			namedParameters.put("HASTA", criteria.getHasta());
			query.append(" AND bot.fecha_beneficio <= :HASTA ");
		}

		Object[] ret = buildQueryFiltros(filtros);
		String queryFiltVars = (String) ret[0];
		Map<String, Object> queryFiltParams = (Map<String, Object>) ret[1];
		String sbQueryFiltVars = (String) ret[2];
		Map<String, Object> sbQueryFiltParams = (Map<String, Object>) ret[3];
		namedParameters.putAll(sbQueryFiltParams);
		System.out.println("queryFiltVars: " + queryFiltVars);
		System.out.println("queryFiltParams: " + queryFiltParams);
		System.out.println("sbQueryFiltParams: " + sbQueryFiltParams);
		System.out.println("sbQFV: " + sbQueryFiltVars);
		System.out.println("filtros: " + filtros);

		query.append(queryFiltVars);

		query.append(" GROUP BY area.codigo, area.nombre, subarea.codigo, subarea.nombre, sede.codigo, sede.nombre, ");
		query.append(" prog.codigo, prog.nombre, subp.codigo, subp.nombre, emp.nit_idupa, emp.razon_social ");
		query.append(" ORDER BY prog.nombre, subp.nombre, emp.nit_idupa");
		System.out.println("queyr: " + query);
		Collection<BeneficioOtorgadoEmpresaVO> beneficios = getNamedParameterJdbcTemplate()
				.query(query.toString(), namedParameters,
						new RowMapper<BeneficioOtorgadoEmpresaVO>() {

							public BeneficioOtorgadoEmpresaVO mapRow(
									ResultSet rs, int rowNum)
									throws SQLException {
								BeneficioOtorgadoEmpresaVO vo = new BeneficioOtorgadoEmpresaVO();
								vo.setAreaCodigo(rs.getLong("AREA_CODIGO"));
								vo.setNombreArea(rs.getString("AREA_NOMBRE"));
								vo.setSubareaCodigo(rs
										.getLong("SUBAREA_CODIGO"));
								vo.setNombreSubarea(rs
										.getString("SUBAREA_NOMBRE"));
								vo.setSedeCodigo(rs.getLong("SEDE_CODIGO"));
								vo.setNombreSede(rs.getString("SEDE_NOMBRE"));
								vo.setProgramaCodigo(rs
										.getLong("PROGRAMA_CODIGO"));
								vo.setNombrePrograma(rs
										.getString("PROGRAMA_NOMBRE"));
								vo.setSbprCodigo(rs
										.getLong("SUBPROGRAMA_CODIGO"));
								vo.setNombreSubprograma(rs
										.getString("SUBPROGRAMA_NOMBRE"));
								vo.setNumeroBeneficios(rs
										.getInt("NUMERO_BENEFICIOS"));
								vo.setValorTotal(rs.getLong("VALOR_TOTAL"));
								vo.setPresupTotEjecutado(rs
										.getLong("PRESUP_TOT_EJECUTADO"));
								vo.getEmpresaVO().setNitIdupa(
										rs.getString("NIT_IDUPA"));
								vo.getEmpresaVO().setRazonSocial(
										rs.getString("RAZON_SOCIAL"));
								return vo;
							}
						});

		Long totalBeneficios = 0L;
		Integer numeroBeneficios = 0;
		Long totalBeneficiarios = 0L;
		Long presupTotEjecutado = 0L;
		Iterator<BeneficioOtorgadoEmpresaVO> it = beneficios.iterator();
		while (it.hasNext()) {
			BeneficioOtorgadoEmpresaVO vo = it.next();
			totalBeneficios += vo.getValorTotal();
			numeroBeneficios += vo.getNumeroBeneficios();
			presupTotEjecutado += vo.getPresupTotEjecutado();
		}
		// ultima posicion - agregar fila totales.
		if (!beneficios.isEmpty()) {
			BeneficioOtorgadoEmpresaVO v = new BeneficioOtorgadoEmpresaVO();
			v.setValorTotal(totalBeneficios);
			v.setNumeroBeneficios(numeroBeneficios);
			v.setPresupTotEjecutado(presupTotEjecutado);
			beneficios.add(v);
		}
		return beneficios;
	}

	public Collection<ProgramaVO> findProgramasEntregados() {
		String query = "SELECT DISTINCT prog.* FROM tcs_ben_programa prog "
				+ " JOIN tcs_ben_subprograma subp "
				+ " ON prog.codigo = subp.prg_codigo "
				+ " JOIN TCS_BOT_EMPRESA bot "
				+ " ON bot.sbpr_codigo = subp.codigo "
				+ " ORDER BY prog.nombre ";

		Collection<ProgramaVO> programas = new ArrayList<ProgramaVO>();
		programas = getNamedParameterJdbcTemplate().getJdbcOperations().query(
				query, new RowMapper<ProgramaVO>() {

					public ProgramaVO mapRow(ResultSet rs, int rowNum)
							throws SQLException {
						ProgramaVO vo = new ProgramaVO();
						vo.setCode(rs.getLong("CODIGO"));
						vo.setCodePrograma(rs.getString("CODIGO"));
						vo.setNombre(rs.getString("NOMBRE"));
						vo.setDescripcion(rs.getString("DESCRIPCION"));
						vo.setObjetivo(rs.getString("OBJETIVO"));
						vo.setPoblacionObjetivo(rs
								.getString("POBLACION_OBJETIVO"));
						vo.setVigencia(rs.getString("VIGENCIA"));
						vo.setDesdeVigencia(rs.getString("DESDE_VIGENCIA"));
						vo.setHastaVigencia(rs.getString("HASTA_VIGENCIA"));
						return vo;
					}
				});
		return programas;
	}

	public Collection<ProgramaVO> findProgramasEntregadosByCriteria(
			EmpresaVO criteria) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		StringBuilder query = new StringBuilder();
		query.append("SELECT DISTINCT prog.* ");
		query.append("FROM tcs_ben_programa prog ");
		query.append(" JOIN tcs_ben_subprograma subp ");
		query.append(" ON prog.codigo = subp.prg_codigo ");
		query.append(" JOIN TCS_BOT_EMPRESA bot ");
		query.append(" ON bot.sbpr_codigo = subp.codigo ");
		query.append(" JOIN TCS_EMPRESA emp ");
		query.append(" ON bot.EMP_CODIGO = emp.CODIGO ");
		query.append(" WHERE 1=1 ");

		if (criteria != null) {
			if (criteria.getCodigo() != null) {
				query.append(" AND bot.EMP_CODIGO = :EMP_CODIGO ");
				namedParameters.put("EMP_CODIGO", criteria.getCodigo());
			}
			if (criteria.getRazonSocial() != null) {
				query.append(" AND UPPER(emp.RAZON_SOCIAL) = UPPER(:RAZON_SOCIAL) ");
				namedParameters.put("RAZON_SOCIAL", criteria.getRazonSocial());
			}
		}

		query.append(" ORDER BY prog.nombre ");

		Collection<ProgramaVO> programas = new ArrayList<ProgramaVO>();
		programas = getNamedParameterJdbcTemplate().query(query.toString(),
				namedParameters, new RowMapper<ProgramaVO>() {

					public ProgramaVO mapRow(ResultSet rs, int rowNum)
							throws SQLException {
						ProgramaVO vo = new ProgramaVO();
						vo.setCode(rs.getLong("CODIGO"));
						vo.setCodePrograma(rs.getString("CODIGO"));
						vo.setNombre(rs.getString("NOMBRE"));
						vo.setDescripcion(rs.getString("DESCRIPCION"));
						vo.setObjetivo(rs.getString("OBJETIVO"));
						vo.setPoblacionObjetivo(rs
								.getString("POBLACION_OBJETIVO"));
						vo.setVigencia(rs.getString("VIGENCIA"));
						vo.setDesdeVigencia(rs.getString("DESDE_VIGENCIA"));
						vo.setHastaVigencia(rs.getString("HASTA_VIGENCIA"));
						return vo;
					}
				});
		return programas;
	}

	public Collection<SubprogramaVO> findSubprogramasEntregados(
			Long codePrograma) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();
		String query = " SELECT DISTINCT subp.* FROM tcs_ben_programa prog "
				+ " JOIN tcs_ben_subprograma subp "
				+ " ON prog.codigo = subp.prg_codigo "
				+ " JOIN TCS_BOT_EMPRESA bot "
				+ " ON bot.sbpr_codigo = subp.codigo "
				+ " AND subp.prg_codigo = :CODIGO_PROGRAMA "
				+ " ORDER BY subp.nombre ";
		namedParameters.put("CODIGO_PROGRAMA", codePrograma);

		Collection<SubprogramaVO> subprogramas = new ArrayList<SubprogramaVO>();

		subprogramas = getNamedParameterJdbcTemplate().query(query,
				namedParameters, new RowMapper<SubprogramaVO>() {

					public SubprogramaVO mapRow(ResultSet rs, int rowNum)
							throws SQLException {
						SubprogramaVO vo = new SubprogramaVO();
						vo.setCode(rs.getLong("CODIGO"));
						vo.setCodeSubPrograma(rs.getString("CODIGO"));
						vo.setNombre(rs.getString("NOMBRE"));
						vo.setDescripcion(rs.getString("DESCRIPCION"));
						vo.setDesdeVigencia(rs.getString("DESDE_VIGENCIA"));
						vo.setHastaVigencia(rs.getString("HASTA_VIGENCIA"));
						return vo;
					}
				});
		return subprogramas;
	}

	public Collection<EmpresaVO> findAllEmpresas() {
		String query = " SELECT * FROM TCS_EMPRESA ORDER BY RAZON_SOCIAL ";

		Collection<EmpresaVO> empresas = new ArrayList<EmpresaVO>();

		empresas = getNamedParameterJdbcTemplate().query(query,
				new HashMap<String, Object>(), new RowMapper<EmpresaVO>() {

					@Override
					public EmpresaVO mapRow(ResultSet rs, int arg1)
							throws SQLException {
						EmpresaVO vo = new EmpresaVO();
						vo.setCodigo(rs.getLong("CODIGO"));
						vo.setTipoDocumento(rs.getString("TIPO_DOCUMENTO"));
						vo.setNitIdupa(rs.getString("NIT_IDUPA"));
						vo.setIdBiometrico(rs.getString("ID_BIOMETRICO"));
						vo.setNombreUpa(rs.getString("NOMBRE_UPA"));
						vo.setRazonSocial(rs.getString("RAZON_SOCIAL"));
						vo.setNomRepLegal(rs.getString("NOM_REP_LEGAL"));
						vo.setDocRepLegal(rs.getString("DOC_REP_LEGAL"));
						vo.setVflCodigoComuna(rs.getLong("VFL_CODIGO_COMUNA"));
						vo.setVflCodigoBarrio(rs.getLong("VFL_CODIGO_BARRIO"));
						vo.setVflCodigoZona(rs.getLong("VFL_CODIGO_ZONA"));
						vo.setNombreContacto(rs.getString("NOMBRE_CONTACTO"));
						vo.setDireccion(rs.getString("DIRECCION"));
						vo.setTelefono(rs.getString("TELEFONO"));
						vo.setSector(rs.getString("SECTOR"));
						vo.setSubSector(rs.getString("SUBSECTOR"));
						vo.setNumeroComodato(rs.getString("NUMERO_COMODATO"));
						vo.setEmail(rs.getString("EMAIL"));
						vo.setObservaciones(rs.getString("OBSERVACIONES"));
						return vo;
					}
				});
		return empresas;
	}

	// Obsoleto
	public Collection<ProgramaVO> findProgramasParaEmpresa() {
		String query = " SELECT * FROM TCS_BEN_PROGRAMA WHERE CAMPO_A4 = 'S' "
				+ " ORDER BY NOMBRE ";
		Collection<ProgramaVO> programas = new ArrayList<ProgramaVO>();
		programas = getNamedParameterJdbcTemplate().query(query,
				new HashMap<String, Object>(), new RowMapper<ProgramaVO>() {

					public ProgramaVO mapRow(ResultSet rs, int rowNum)
							throws SQLException {
						ProgramaVO vo = new ProgramaVO();
						vo.setCode(rs.getLong("CODIGO"));
						vo.setCodePrograma(rs.getString("CODIGO"));
						vo.setNombre(rs.getString("NOMBRE"));
						vo.setDescripcion(rs.getString("DESCRIPCION"));
						vo.setObjetivo(rs.getString("OBJETIVO"));
						vo.setPoblacionObjetivo(rs
								.getString("POBLACION_OBJETIVO"));
						vo.setVigencia(rs.getString("VIGENCIA"));
						vo.setDesdeVigencia(rs.getString("DESDE_VIGENCIA"));
						vo.setHastaVigencia(rs.getString("HASTA_VIGENCIA"));
						return vo;
					}
				});
		return programas;
	}

	// obsoleto
	public Collection<SubprogramaVO> findSubprogramasParaEmpresa(
			Long codePrograma) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();
		String query = " SELECT * FROM TCS_BEN_SUBPROGRAMA WHERE CAMPO_A4 = 'S' "
				+ " AND PRG_CODIGO = :PRG_CODIGO ORDER BY NOMBRE ";
		namedParameters.put("PRG_CODIGO", codePrograma);

		Collection<SubprogramaVO> subprogramas = new ArrayList<SubprogramaVO>();

		subprogramas = getNamedParameterJdbcTemplate().query(query,
				namedParameters, new RowMapper<SubprogramaVO>() {

					public SubprogramaVO mapRow(ResultSet rs, int rowNum)
							throws SQLException {
						SubprogramaVO vo = new SubprogramaVO();
						vo.setCode(rs.getLong("CODIGO"));
						vo.setCodeSubPrograma(rs.getString("CODIGO"));
						vo.setNombre(rs.getString("NOMBRE"));
						vo.setDescripcion(rs.getString("DESCRIPCION"));
						vo.setDesdeVigencia(rs.getString("DESDE_VIGENCIA"));
						vo.setHastaVigencia(rs.getString("HASTA_VIGENCIA"));
						return vo;
					}
				});
		return subprogramas;
	}

	/**
	 * HACK.. Metodo que retorna un Object[] que contiene los strings y
	 * parametros a concatenar en la consulta del metodo
	 * findBeneficiosBeneficiariosComuna.
	 * 
	 * @param filtros
	 * @return Array de Object, primer posicion String a concatenar (ej:
	 *         "AND emp.FECHA_NACIMIENTO >= TO_DATE('01/01/2000')", segunda
	 *         posicion List parametros query, tercera posicion string a
	 *         concatenar subquery, cuarta posicion List parametros subquery.
	 */
	private Object[] buildQueryFiltros(Collection<CondicionConsultaVO> filtros) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		List<CondicionConsultaVO> lFiltros = (List<CondicionConsultaVO>) filtros;
		CondicionConsultaVO filtro = null;
		Object[] ret = new Object[4];
		StringBuffer query = new StringBuffer();
		StringBuffer sbQuery = new StringBuffer();
		List<Object> queryParams = new ArrayList<Object>();
		List<Object> sbQueryParams = new ArrayList<Object>();

		if ((Object) filtros != null) {
			for (int i = 0; i < lFiltros.size(); i++) {
				filtro = (CondicionConsultaVO) lFiltros.get(i);
				String operador = filtro.getCodFiltro();
				String tipoDato = filtro.getTipoCampo();

				// Esto se hace por problema de nombre del filtro, conflicto con
				// el tipo_documento de beneficiario. Se cambia aqui a
				// tipo_documento.
				// Si, yo se que es un hack.
				if (filtro.getCodcampo().equals(
						FiltrosReportesUtil.TIPO_DOCUMENTO_EMPRESA)) {
					filtro.setCodcampo(FiltrosReportesUtil.TIPO_DOCUMENTO);
				}

				query.append(" AND ");
				sbQuery.append(" AND ");
				if (tipoDato.equals(FiltrosReportesUtil.TIPO_NUMERICO)) {

					if (filtro.getCodcampo().equals(FiltrosReportesUtil.EDAD)) {
						String fechaIni = "";
						String fechaFin = "";
						int edad1 = Integer.parseInt(filtro.getValor());
						fechaIni = FiltrosReportesUtil
								.convertAgeToDateOfBirth(edad1);
						if (operador.equals(FiltrosReportesUtil.ENTRE)) {
							int edad2 = Integer.parseInt(filtro.getValor2());
							fechaFin = FiltrosReportesUtil
									.convertAgeToDateOfBirth(edad2);
						}
						if (operador.equals(FiltrosReportesUtil.ENTRE)) {
							// se invierte el orden de las fechas.
							query.append("emp."
									+ FiltrosReportesUtil.FECHA_NACIMIENTO
									+ " " + FiltrosReportesUtil.ENTRE
									+ " TO_DATE(:fechaFin_" + i
									+ ", 'dd/mm/rrrr') AND TO_DATE(:fechaIni_"
									+ i + ", 'dd/mm/rrrr')");

							sbQuery.append("emp_."
									+ FiltrosReportesUtil.FECHA_NACIMIENTO
									+ " " + FiltrosReportesUtil.ENTRE
									+ " TO_DATE(:fechaFin_" + i
									+ ", 'dd/mm/rrrr') AND TO_DATE(:fechaIni_"
									+ i + ", 'dd/mm/rrrr')");

							namedParameters.put("fechaFin_" + i, fechaFin);
							namedParameters.put("fechaIni_" + i, fechaIni);

						} else {// se invierten los operadores debido a que
								// ahora se comparan fechas y no edades.
							if (operador.equals(FiltrosReportesUtil.MAYOR)) {
								operador = FiltrosReportesUtil.MENOR;
							} else if (operador
									.equals(FiltrosReportesUtil.MAYOR_IGUAL)) {
								operador = FiltrosReportesUtil.MENOR_IGUAL;
							} else if (operador
									.equals(FiltrosReportesUtil.MENOR)) {
								operador = FiltrosReportesUtil.MAYOR;
							} else if (operador
									.equals(FiltrosReportesUtil.MENOR_IGUAL)) {
								operador = FiltrosReportesUtil.MAYOR_IGUAL;
							}
							query.append("emp."
									+ FiltrosReportesUtil.FECHA_NACIMIENTO
									+ " " + operador + " TO_DATE(:fechaIni_"
									+ i + ", 'dd/mm/rrrr')");

							sbQuery.append("ben_."
									+ FiltrosReportesUtil.FECHA_NACIMIENTO
									+ " " + operador + " TO_DATE(:fechaIni_"
									+ i + ", 'dd/mm/rrrr')");
							namedParameters.put("fechaIni_" + i, fechaIni);
						}
						continue;
					}

					if (operador.equals(FiltrosReportesUtil.IGUAL)
							|| operador.equals(FiltrosReportesUtil.DIFERENTE)
							|| operador.equals(FiltrosReportesUtil.MENOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MAYOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MENOR)
							|| operador.equals(FiltrosReportesUtil.MAYOR)) {
						query.append(" emp." + filtro.getCodcampo() + " "
								+ operador + " :filtro.valor_" + i + " ");
						namedParameters.put("filtro.valor_" + i,
								filtro.getValor());
						sbQuery.append(" emp_." + filtro.getCodcampo() + " "
								+ operador + " :filtro.valor_" + i + " ");

					} else {// BETWEEN
						query.append("emp." + filtro.getCodcampo() + " "
								+ operador + " :filtro.valor_" + i
								+ " AND :filtro.valor2_" + i + " ");
						sbQuery.append("emp_." + filtro.getCodcampo() + " "
								+ operador + " :filtro.valor_" + i
								+ " AND :filtro.valor2_" + i + " ");
						namedParameters.put("filtro.valor_" + i,
								filtro.getValor());
						namedParameters.put("filtro.valor2_" + i,
								filtro.getValor2());

					}

				} else if (tipoDato.equals(FiltrosReportesUtil.TIPO_FECHA)) {

					if (operador.equals(FiltrosReportesUtil.ENTRE)
							|| operador.equals(FiltrosReportesUtil.IGUAL)) {
						query.append("emp." + filtro.getCodcampo() + " "
								+ operador + " TO_DATE(:filtro.valor_" + i
								+ ", 'dd/mm/rrrr') AND TO_DATE(:filtro.valor2_"
								+ i + ",'dd/mm/rrrr')");
						namedParameters.put("filtro.valor_" + i,
								filtro.getValor());
						namedParameters.put("filtro.valor2_" + i,
								filtro.getValor2());
						sbQuery.append("emp_." + filtro.getCodcampo() + " "
								+ operador + " TO_DATE(:filtro.valor_" + i
								+ ", 'dd/mm/rrrr') AND TO_DATE(:filtro.valor2_"
								+ i + ", 'dd/mm/rrrr')");

					} else {
						query.append("emp." + filtro.getCodcampo() + " "
								+ operador + " TO_DATE(:filtro.valor_" + i
								+ ", 'dd/mm/rrrr')");
						namedParameters.put("filtro.valor_" + i,
								filtro.getValor());
						sbQuery.append("emp_." + filtro.getCodcampo() + " "
								+ operador + " TO_DATE(:filtro.valor_" + i
								+ ", 'dd/mm/rrrr')");

					}

				} else if (tipoDato
						.equals(FiltrosReportesUtil.TIPO_ALFANUMERICO)
						|| tipoDato.equals("L")) {
					if (operador.equals(FiltrosReportesUtil.IGUAL)
							|| operador.equals(FiltrosReportesUtil.DIFERENTE)) {
						query.append(" UPPER(emp." + filtro.getCodcampo()
								+ " ) " + operador + " :filtro.valor_" + i
								+ " ");
						namedParameters.put("filtro.valor_" + i, filtro
								.getValor().toUpperCase());
						sbQuery.append(" UPPER(emp_." + filtro.getCodcampo()
								+ " ) " + operador + " :filtro.valor_" + i
								+ " ");

					} else if (operador.equals(FiltrosReportesUtil.PARECIDO)) {
						query.append(" UPPER(emp." + filtro.getCodcampo()
								+ " ) " + FiltrosReportesUtil.PARECIDO
								+ " :filtro.valor_" + i + " ");
						namedParameters.put("filtro.valor_" + i, "%"
								+ filtro.getValor().toUpperCase() + "%");
						sbQuery.append(" UPPER(emp_." + filtro.getCodcampo()
								+ " ) " + FiltrosReportesUtil.PARECIDO
								+ " :filtro.valor_" + i + " ");

					}
				} else {
					if (operador.equals(FiltrosReportesUtil.IGUAL)
							|| operador.equals(FiltrosReportesUtil.DIFERENTE)
							|| operador.equals(FiltrosReportesUtil.MENOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MAYOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MENOR)
							|| operador.equals(FiltrosReportesUtil.MAYOR)) {
						query.append(" emp." + filtro.getCodcampo() + " "
								+ operador + " :filtro.valor_" + i + " ");
						namedParameters.put("filtro.valor_" + i,
								filtro.getValor());
						query.append(" emp_." + filtro.getCodcampo() + " "
								+ operador + " :filtro.valor_" + i + " ");

					} else { // BETWEEN
						query.append("emp." + filtro.getCodcampo() + " "
								+ operador + " :filtro.valor_" + i
								+ " AND :filtro.valor2_" + i + " ");
						namedParameters.put("filtro.valor_" + i,
								filtro.getValor());
						namedParameters.put("filtro.valor2_" + i,
								filtro.getValor2());
						sbQuery.append("emp_." + filtro.getCodcampo() + " "
								+ operador + " :filtro.valor_" + i
								+ " AND :filtro.valor2_" + i + " ");

					}

				}

			}
		}
		ret[0] = query.toString();
		// ret[1] = queryParams;
		ret[1] = namedParameters;
		ret[2] = sbQuery.toString();
		// ret[3] = sbQueryParams;
		ret[3] = namedParameters;
		// System.out.println("retorno: " + retorno);
		return ret;
	}

	public ReporteTotalComunaVO findFiltersComuna(ReporteTotalComunaVO objRtcVO) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		String strQuery = null;

		if (objRtcVO.getCodeComuna() != null) {
			strQuery = "SELECT NOMBRE FROM PAOYER.TCS_VALOR_FLEXIBLE "
					+ " WHERE CODIGO = :CODIGO ";
			namedParameters.put("CODIGO", objRtcVO.getCodeComuna());
			try {
				String nombre = getNamedParameterJdbcTemplate().queryForObject(
						strQuery, namedParameters, String.class);
				objRtcVO.setNombreComuna(nombre);
			} catch (IncorrectResultSizeDataAccessException e) {
			}

		}
		if (objRtcVO.getCodePrograma() != null) {
			strQuery = "SELECT NOMBRE FROM TCS_BEN_PROGRAMA "
					+ " WHERE CODIGO = :CODIGO ";
			namedParameters.clear();
			namedParameters.put("CODIGO", objRtcVO.getCodePrograma());
			try {
				String nombre = getNamedParameterJdbcTemplate().queryForObject(
						strQuery, namedParameters, String.class);
				objRtcVO.setNombrePrograma(nombre);
			} catch (IncorrectResultSizeDataAccessException e) {
			}
		}
		if (objRtcVO.getCodeSubprograma() != null) {
			strQuery = "SELECT NOMBRE FROM TCS_BEN_SUBPROGRAMA "
					+ " WHERE CODIGO = :CODIGO ";
			namedParameters.clear();
			namedParameters.put("CODIGO", objRtcVO.getCodeSubprograma());
			try {
				String nombre = getNamedParameterJdbcTemplate().queryForObject(
						strQuery, namedParameters, String.class);
				objRtcVO.setNombreSubprograma(nombre);
			} catch (IncorrectResultSizeDataAccessException e) {
			}
		}
		return objRtcVO;
	}

	public Collection<ReportComunaVO> findBeneficiosEmpresasComuna(
			ReporteTotalComunaVO criteria,
			Collection<CondicionConsultaVO> filtros) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		// parte adicional de la consulta (criterios de busqueda.)
		StringBuffer queryVars = new StringBuffer();
		List<Object> parametersQueryVars = new ArrayList<Object>();
		StringBuffer sbQueryVars = new StringBuffer();
		List<Object> parametersSbQueryVars = new ArrayList<Object>();

		if ((Object) criteria.getCodeZona() != null) {
			queryVars.append(" AND (ben.vfl_codigo_zona = :VFL_CODIGO_ZONA ");
			sbQueryVars
					.append(" AND (ben_.vfl_codigo_zona = :VFL_CODIGO_ZONA ");
			namedParameters.put("VFL_CODIGO_ZONA", criteria.getCodeZona());
			// si tiene elegida una zona, pero no tiene elegida una comuna..
			if ((Object) criteria.getCodeComuna() == null) {

				Collection<VflexVO> comunas = vflexServiceImpl.findVflex(
						"COMUNA",
						Long.toString(criteria.getCodeZona().longValue()));
				Iterator<VflexVO> it = comunas.iterator();
				while (it.hasNext()) {
					VflexVO vflexVO = (VflexVO) it.next();
					queryVars
							.append(" OR ben.vfl_codigo_comuna = :VFL_CODIGO_COMUNA ");
					sbQueryVars
							.append(" OR ben_.vfl_codigo_comuna = :VFL_CODIGO_COMUNA ");
					namedParameters.put("VFL_CODIGO_COMUNA", vflexVO.getCode());
				}
			}
			queryVars.append(" ) ");
			sbQueryVars.append(" ) ");
		}

		if ((Object) criteria.getCodeComuna() != null) {
			queryVars.append(" AND comuna.CODIGO = :comuna.CODIGO ");
			sbQueryVars.append(" AND comuna_.CODIGO = :comuna.CODIGO ");
			namedParameters.put("comuna.CODIGO", criteria.getCodeComuna());
		}
		if ((Object) criteria.getCodeSubprograma() != null) {
			queryVars.append(" AND subpro.CODIGO = :subpro.CODIGO ");
			sbQueryVars.append(" AND subpro_.CODIGO = :subpro.CODIGO ");
			namedParameters.put("subpro.CODIGO", criteria.getCodeSubprograma());
		}
		if ((Object) criteria.getCodePrograma() != null) {
			queryVars.append(" AND prog.CODIGO = :prog.CODIGO ");
			sbQueryVars.append(" AND prog_.CODIGO = :prog.CODIGO ");
			namedParameters.put("prog.CODIGO", criteria.getCodePrograma());
		}
		if ((Object) criteria.getDesde() != null
				&& (Object) criteria.getHasta() != null) {
			queryVars
					.append(" AND beneotor.FECHA_BENEFICIO BETWEEN TO_DATE(:DESDE,'dd/mm/rrrr') AND TO_DATE(:HASTA,'dd/mm/rrrr') ");
			sbQueryVars
					.append(" AND beneotor_.FECHA_BENEFICIO BETWEEN TO_DATE(:DESDE,'dd/mm/rrrr') AND TO_DATE(:HASTA,'dd/mm/rrrr') ");
			namedParameters.put("DESDE", criteria.getDesde());
			namedParameters.put("HASTA", criteria.getHasta());
		}
		if ((Object) criteria.getDesde() != null
				&& (Object) criteria.getHasta() == null) {
			queryVars
					.append(" AND beneotor.FECHA_BENEFICIO >= TO_DATE(:DESDE,'dd/mm/rrrr') ");
			sbQueryVars
					.append(" AND beneotor_.FECHA_BENEFICIO >= TO_DATE(:DESDE,'dd/mm/rrrr')");
			namedParameters.put("DESDE", criteria.getDesde());
		}
		if ((Object) criteria.getDesde() == null
				&& (Object) criteria.getHasta() != null) {
			queryVars
					.append(" AND beneotor.FECHA_BENEFICIO <= TO_DATE(:HASTA,'dd/mm/rrrr') ");
			sbQueryVars
					.append(" AND beneotor_.FECHA_BENEFICIO <= TO_DATE(:HASTA,'dd/mm/rrrr') ");
			namedParameters.put("HASTA", criteria.getHasta());
		}

		Object[] ret = buildQueryFiltros(filtros);
		String queryFiltVars = (String) ret[0];
		Map<String, Object> queryFiltParams = (Map<String, Object>) ret[1];
		String sbQueryFiltVars = (String) ret[2];
		Map<String, Object> sbQueryFiltParams = (Map<String, Object>) ret[3];
		namedParameters.putAll(sbQueryFiltParams);

		StringBuffer queryy = new StringBuffer();
		queryy.append(" SELECT COUNT(DISTINCT beneotor.emp_codigo) contbeneficiario, ");
		queryy.append(" COUNT(beneotor.CODIGO) contbeneficio, ");
		queryy.append(" SUM(beneotor.VALOR_BENEFICIO) valor, comuna.NOMBRE nomcomuna, prog.NOMBRE nompro, subpro.NOMBRE nomsubpro ,  ");
		// --subquery

		queryy.append(" (SELECT COUNT(DISTINCT emp_.codigo) ");
		queryy.append(" FROM TCS_BEN_AREA subarea_ JOIN TCS_BEN_SUBPROGRAMA subpro_ ON subarea_.codigo = subpro_.area_codigo ");
		queryy.append(" JOIN TCS_BOT_EMPRESA beneotor_ ON beneotor_.sbpr_codigo = subpro_.codigo ");
		queryy.append(" JOIN TCS_EMPRESA emp_ ON beneotor_.emp_codigo = emp_.codigo ");
		queryy.append(" JOIN TCS_BEN_PROGRAMA prog_ ON subpro_.prg_codigo = prog_.codigo ");
		queryy.append(" JOIN TCS_BEN_AREA area_ ON area_.codigo = prog_.area_codigo ");
		queryy.append(" LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE comuna_ ON emp_.vfl_codigo_comuna = comuna_.codigo  ");
		queryy.append(" WHERE prog_.vigencia='A' and subpro_.vigencia='A' ");
		queryy.append(sbQueryVars.toString());
		queryy.append(sbQueryFiltVars);
		queryy.append(") AS TOTAL_BENEFICIARIOS ");
		queryy.append(", area.NOMBRE nombre_secretaria ");
		queryy.append(" FROM TCS_BEN_AREA subarea ");
		queryy.append(" JOIN TCS_BEN_SUBPROGRAMA subpro ");
		queryy.append(" ON subarea.codigo = subpro.area_codigo ");
		queryy.append(" JOIN TCS_BOT_EMPRESA beneotor ");
		queryy.append(" ON beneotor.sbpr_codigo = subpro.codigo ");
		queryy.append(" JOIN TCS_EMPRESA emp ");
		queryy.append(" ON beneotor.EMP_CODIGO = emp.codigo ");
		queryy.append(" JOIN TCS_BEN_PROGRAMA prog ");
		queryy.append(" ON subpro.prg_codigo = prog.codigo ");
		queryy.append(" JOIN TCS_BEN_AREA area ");
		queryy.append(" ON area.codigo = subpro.area_codigo ");
		queryy.append(" LEFT OUTER JOIN PAOYER.TCS_VALOR_FLEXIBLE comuna ");
		queryy.append(" ON emp.vfl_codigo_comuna = comuna.codigo ");
		queryy.append(" WHERE prog.vigencia='A' and subpro.vigencia='A' ");

		queryy.append(queryVars.toString());
		queryy.append(queryFiltVars);

		if (criteria.getTipoReporte().equals(
				ReporteTotalComunaService.TIPO_REPORTE_1)) {
			queryy.append(" GROUP BY area.nombre, comuna.NOMBRE, prog.NOMBRE,subpro.NOMBRE ");
			queryy.append(" ORDER BY area.nombre, comuna.NOMBRE, prog.NOMBRE,subpro.NOMBRE ");
		} else if (criteria.getTipoReporte().equals(
				ReporteTotalComunaService.TIPO_REPORTE_2)) {
			queryy.append(" GROUP BY comuna.NOMBRE, area.nombre, prog.NOMBRE, subpro.NOMBRE ");
			queryy.append(" ORDER BY comuna.NOMBRE, area.nombre, prog.NOMBRE, subpro.NOMBRE ");
		}

		Collection<ReportComunaVO> lbeneotor = new ArrayList<ReportComunaVO>();

		System.out.println("queryy: " + queryy.toString());
		for (String str : namedParameters.keySet()) {
			System.out
					.println("namedP " + str + ":" + namedParameters.get(str));
		}
		ReportComunaVO objbeneficios = null;
		long totalvalor = 0;
		long totalben = 0; // total beneficios
		long totalber = 0; // total beneficiarios
		int firstRow = 0;

		List<Map<String, Object>> rows = getNamedParameterJdbcTemplate()
				.queryForList(queryy.toString(), namedParameters);
		for (Map<String, Object> row : rows) {
			ReportComunaVO vo = new ReportComunaVO();
			vo.setNombrePrograma((String) row.get("nompro"));
			vo.setNombreSubprograma((String) row.get("nomsubpro"));
			vo.setNombreComuna((String) row.get("nomcomuna"));
			vo.setNombreSecretaria((String) row.get("nombre_secretaria"));

			BigDecimal contBeneficio = (BigDecimal) row.get("contbeneficio");
			if (contBeneficio != null) {
				vo.setContben(contBeneficio.longValueExact());
			}
			BigDecimal contBeneficiario = (BigDecimal) row
					.get("contbeneficiario");
			if (contBeneficiario != null) {
				vo.setContber(contBeneficiario.longValueExact());
			}
			BigDecimal valor = (BigDecimal) row.get("valor");
			if (valor != null) {
				vo.setValor(valor.longValueExact());
			}
			if (valor != null) {
				totalvalor += valor.longValueExact();
			}
			if (contBeneficio != null) {
				totalben += contBeneficio.longValueExact();
			}

			if (firstRow == 0) {
				BigDecimal totalBeneficiarios = (BigDecimal) row
						.get("TOTAL_BENEFICIARIOS");
				if (totalBeneficiarios != null) {
					totalber = totalBeneficiarios.longValueExact();
				}
				firstRow++;
			}
			lbeneotor.add(vo);
		}

		if (lbeneotor.size() > 0) {
			objbeneficios = new ReportComunaVO();
			objbeneficios.setNombreComuna("VALOR TOTAL");
			objbeneficios.setContben(totalben);
			objbeneficios.setContber(totalber);
			objbeneficios.setValor(totalvalor);
			lbeneotor.add(objbeneficios);
			objbeneficios = null;
		}
		return lbeneotor;
	}

	/*
	 * public Collection<String> findAtributosSAB() { Map<String, Object>
	 * namedParameters = new HashMap<String, Object>();
	 * 
	 * // consulta nombres unicos sab. StringBuffer query = new StringBuffer();
	 * query.append(
	 * " SELECT DISTINCT sabout.nombre FROM tcs_ben_subp_atr_beneficiario sabout "
	 * ); query.append(" JOIN tcs_ben_subprograma subp ");
	 * query.append(" ON sabout.sbpr_codigo = subp.codigo ");
	 * query.append(" AND sabout.nombre IN "); query.append(" ( ");
	 * query.append(
	 * " SELECT DISTINCT sab.nombre FROM tcs_ben_subp_atr_beneficiario sab ");
	 * query.append(" WHERE sab.codigo IN "); query.append(" ( ");
	 * query.append(" SELECT DISTINCT ba.sab_codigo ");
	 * query.append(" FROM tcs_ben_beneficio_atributo ba ");
	 * query.append(" JOIN tcs_ben_beneficio_otorgado bot ");
	 * query.append(" ON ba.bot_codigo = bot.codigo ");
	 * query.append(" WHERE bot.campo_n3 IS NOT NULL "); query.append(" ) ");
	 * query.append(" ) "); query.append(" WHERE subp.campo_a4 = 'S' ");
	 * 
	 * Collection<String> nombres = getNamedParameterJdbcTemplate()
	 * .getJdbcOperations().query(query.toString(), new RowMapper<String>() {
	 * public String mapRow(ResultSet rs, int rowNum) throws SQLException {
	 * String nombre = rs.getString("nombre"); return nombre; } });
	 * Collection<SubprogramaAtributoBeneficiario> sab = new
	 * ArrayList<SubprogramaAtributoBeneficiario>(); // buscar valores posibles
	 * para estos sab. if (nombres != null && !nombres.isEmpty()) { query = new
	 * StringBuffer(); query.append(" SELECT * FROM tcs_ben_ "); for (String
	 * nombre : nombres) { namedParameters.put("nombre", nombre);
	 * 
	 * } } }
	 */
	public Collection<BeneficioOtorgadoEmpresaVO> findResumenBeneficioOtorgadoDetByCriteria(
			RepEmpresaVO criteria) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		StringBuffer query = new StringBuffer(
				" SELECT COUNT(beneotor.codigo) cantidad_otorgada, sede.CODIGO codsede, "
						+ " sede.NOMBRE nomsede, prog.CODIGO codpro, prog.NOMBRE nompro, "
						+ " subpro.CODIGO codsubpro, subpro.NOMBRE nomsubpro "
						+ " FROM TCS_BEN_PROGRAMA prog "
						+ " JOIN TCS_BEN_SUBPROGRAMA subpro "
						+ " ON subpro.PRG_CODIGO = prog.CODIGO "
						+ " JOIN TCS_BOT_EMPRESA beneotor "
						+ " ON beneotor.SBPR_CODIGO =  subpro.CODIGO "
						+ " JOIN TCS_BEN_SEDE sede "
						+ " ON beneotor.SEDE_CODIGO = sede.CODIGO "
						+ " JOIN TCS_EMPRESA emp "
						+ " ON emp.codigo = beneotor.EMP_CODIGO "
						+ " WHERE prog.vigencia='A' AND subpro.vigencia='A' "
						+ " AND subpro.campo_a4 = 'S' ");

		if ((Object) criteria.getCodeSubprograma() != null) {
			query.append(" AND subpro.CODIGO = :subpro.CODIGO ");
			namedParameters.put("subpro.CODIGO", criteria.getCodeSubprograma());
		}
		if ((Object) criteria.getCodePrograma() != null) {
			query.append(" AND prog.CODIGO = :prog.CODIGO ");
			namedParameters.put("prog.CODIGO", criteria.getCodePrograma());
		}
		if (criteria.getActividadEconomica() != null) {
			query.append(" AND emp.RAZON_SOCIAL = :RAZON_SOCIAL ");
			namedParameters.put("RAZON_SOCIAL",
					criteria.getActividadEconomica());
		}
		if (criteria.getCodeEmpresa() != null) {
			query.append(" AND emp.codigo = :EMP_CODIGO ");
			namedParameters.put("EMP_CODIGO", criteria.getCodeEmpresa());
		}

		if ((Object) criteria.getDesde() != null
				&& (Object) criteria.getHasta() != null) {
			query.append(" AND beneotor.VIGENCIA_BENEFICIO BETWEEN TO_NUMBER(:DESDE,9999) AND TO_NUMBER(:HASTA,9999)");
			namedParameters.put("DESDE", criteria.getDesde());
			namedParameters.put("HASTA", criteria.getHasta());
		}
		query.append(" GROUP BY sede.CODIGO, sede.NOMBRE, prog.CODIGO, prog.NOMBRE, subpro.CODIGO, "
				+ "subpro.NOMBRE");

		query.append(" ORDER BY prog.NOMBRE,subpro.NOMBRE,sede.NOMBRE ");
		System.out.println(query);
		System.out.println(namedParameters.toString());

		Collection<BeneficioOtorgadoEmpresaVO> beneficios = new ArrayList<BeneficioOtorgadoEmpresaVO>();
		final String desde = criteria.getDesde();
		final String hasta = criteria.getHasta();
		beneficios = getNamedParameterJdbcTemplate().query(query.toString(),
				namedParameters, new RowMapper<BeneficioOtorgadoEmpresaVO>() {

					public BeneficioOtorgadoEmpresaVO mapRow(ResultSet rs,
							int rowNum) throws SQLException {
						BeneficioOtorgadoEmpresaVO vo = new BeneficioOtorgadoEmpresaVO();
						vo.setSedeCodigo(rs.getLong("codsede"));
						vo.setNombreSede(rs.getString("nomsede"));
						vo.setProgramaCodigo(rs.getLong("codpro"));
						vo.setNombrePrograma(rs.getString("nompro"));
						vo.setSbprCodigo(rs.getLong("codsubpro"));
						vo.setNombreSubprograma(rs.getString("nomsubpro"));
						vo.setDesde(desde);
						vo.setHasta(hasta);
						vo.setNumeroBeneficios(rs.getInt("cantidad_otorgada"));
						return vo;
					}
				});

		return beneficios;
	}

	public Collection<BeneficioOtorgadoEmpresaVO> findReporteBeneficioOtorgadoDet(
			List<RepAtributoVO> atributosEspecificos,
			List<CondicionConsultaVO> filtros, RepEmpresaVO criteria) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		Collection<ReporteDetVO> beneficiarios = new LinkedList<ReporteDetVO>();
		List<RepAtributoVO> latributosEspecificos = atributosEspecificos;
		// List<RepAtributoVO> latributosGenericos = atributosGenericos;
		RepAtributoVO atrVO = null;

		StringBuffer atriGenerales = new StringBuffer();
		StringBuffer atriEspecificos = new StringBuffer();
		StringBuffer codiEspecificos = new StringBuffer();
		// String filtrosGenerales = "'" + checkFiltros(filtros) + "'";

		// filtrosgenerales
		String filtrosGenerales = buildQueryFiltrosReporteBeneficioOtorgadoDet(filtros);

		int sizeListAtriEsp = latributosEspecificos.size();
		String desde = criteria.getDesde();
		String hasta = criteria.getHasta();

		if (sizeListAtriEsp > 0) {
			for (int i = 0; i < sizeListAtriEsp; i++) {
				atrVO = (RepAtributoVO) latributosEspecificos.get(i);
				codiEspecificos.append(atrVO.getCodigo() + "|");
				atriEspecificos.append(" CAMPO" + (i + 1) + " ");
			}
		}

		namedParameters.put("CamposGenerales", atriGenerales.toString());
		namedParameters.put("CamposEspecificos", sizeListAtriEsp);
		namedParameters.put("codigosCamposEspecificos",
				codiEspecificos.toString());
		namedParameters.put("filtrosGenerales", filtrosGenerales);
		// namedParameters.put("filtrosEspecificos", filtrosEspecificos);
		namedParameters.put("filtrosEspecificos", "");
		namedParameters.put("codigoSede", criteria.getCodeSede());
		namedParameters.put("codigoSub", criteria.getCodeSubprograma());
		namedParameters.put("fechaInicio", desde);
		namedParameters.put("fechaFinal", hasta);
		namedParameters.put("codigoEmp", criteria.getCodeEmpresa());
		namedParameters.put("actividadEc", criteria.getActividadEconomica());
		System.out.println("namedParameters: " + namedParameters.toString());

		// TODO:PCS_REPORTE_BENEFICIO_OTORGADO
		SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(getJdbcTemplate())
				.withSchemaName("BENEFICIOS")
				.withProcedureName("PCS_REPORTE_BOT_EMP")
				.returningResultSet("c_resultado",
						new BeneficioOtorgadoEmpresaVORowMapper());
		SqlParameterSource in = new MapSqlParameterSource()
				.addValues(namedParameters);
		Map<String, Object> out = simpleJdbcCall.execute(in);

		@SuppressWarnings("unchecked")
		Collection<BeneficioOtorgadoEmpresaVO> retorno = (Collection<BeneficioOtorgadoEmpresaVO>) out
				.get("c_resultado");

		return retorno;
	}

	@Override
	public Collection<String> findActividadesEconomicas() {
		Collection<String> actividades = new ArrayList<String>();

		String query = " SELECT DISTINCT RAZON_SOCIAL FROM TCS_EMPRESA ORDER BY RAZON_SOCIAL ";
		try {
			actividades = getNamedParameterJdbcTemplate().getJdbcOperations()
					.queryForList(query, null, String.class);
		} catch (IncorrectResultSizeDataAccessException e) {
		}
		return actividades;
	}

	@Override
	public Collection<EmpresaVO> findEmpresasByActividadEconomica(
			String actividadEconomica) {
		Map<String, Object> namedParameters = new HashMap<String, Object>();

		String query = "SELECT * FROM TCS_EMPRESA WHERE UPPER(RAZON_SOCIAL) = UPPER(:RAZON_SOCIAL) ORDER BY NOMBRE_UPA";

		namedParameters.put("RAZON_SOCIAL", actividadEconomica);
		Collection<EmpresaVO> empresas = new ArrayList<EmpresaVO>();
		try {
			empresas = getNamedParameterJdbcTemplate().query(query,
					namedParameters, new EmpresaVORowMapper());
		} catch (IncorrectResultSizeDataAccessException e) {
		}
		return empresas;
	}

	private String checkFiltrosEspecificos(
			Collection<CondicionConsultaVO> filtros) throws SQLException {
		List<CondicionConsultaVO> lFiltros = (List<CondicionConsultaVO>) filtros;
		CondicionConsultaVO filtro = null;
		StringBuffer retorno = new StringBuffer();
		if ((Object) filtros != null) {
			for (int i = 0; i < lFiltros.size(); i++) {
				filtro = (CondicionConsultaVO) lFiltros.get(i);
				if (filtro.getOrigen().equals("E")) {
					if (filtro.getCodFiltro().equals("=")) {
						retorno.append(" AND NVL(Fcs_Ben_Valor_Atributo("
								+ filtro.getCodcampo()
								+ ", bot.codigo, ben.codigo, bot.FECHA_BENEFICIO),'' '') = TO_CHAR(''"
								+ filtro.getValor().toUpperCase() + "'') ");
					} else if (filtro.getCodFiltro().equals("<>")) {
						retorno.append(" AND NVL(Fcs_Ben_Valor_Atributo("
								+ filtro.getCodcampo()
								+ ", bot.codigo, ben.codigo, bot.FECHA_BENEFICIO),'' '') <> TO_CHAR(''"
								+ filtro.getValor().toUpperCase() + "'') ");
					} else if (filtro.getCodFiltro().equals("<=")) {
						retorno.append(" AND NVL(Fcs_Ben_Valor_Atributo("
								+ filtro.getCodcampo()
								+ ", bot.codigo, ben.codigo, bot.FECHA_BENEFICIO),'' '') <= TO_CHAR(''"
								+ filtro.getValor() + "'') ");
					} else if (filtro.getCodFiltro().equals(">=")) {
						retorno.append(" AND NVL(Fcs_Ben_Valor_Atributo("
								+ filtro.getCodcampo()
								+ ", bot.codigo, ben.codigo, bot.FECHA_BENEFICIO),'' '') >= TO_CHAR(''"
								+ filtro.getValor() + "'') ");
					} else if (filtro.getCodFiltro().equals("<")) {
						retorno.append(" AND NVL(Fcs_Ben_Valor_Atributo("
								+ filtro.getCodcampo()
								+ ", bot.codigo, ben.codigo, bot.FECHA_BENEFICIO),'' '') < TO_CHAR(''"
								+ filtro.getValor() + "'') ");
					} else if (filtro.getCodFiltro().equals(">")) {
						retorno.append(" AND NVL(Fcs_Ben_Valor_Atributo("
								+ filtro.getCodcampo()
								+ ", bot.codigo, ben.codigo, bot.FECHA_BENEFICIO),'' '') > TO_CHAR(''"
								+ filtro.getValor() + "'') ");
					} else if (filtro.getCodFiltro().equals("between")) {
						retorno.append(" AND NVL(Fcs_Ben_Valor_Atributo("
								+ filtro.getCodcampo()
								+ ", bot.codigo, ben.codigo, bot.FECHA_BENEFICIO),'' '') between TO_CHAR(''"
								+ filtro.getValor() + "'') AND TO_CHAR(''"
								+ filtro.getValor2() + "'')");
					} else if (filtro.getCodFiltro().equals("like")) {
						retorno.append(" AND NVL(Fcs_Ben_Valor_Atributo("
								+ filtro.getCodcampo()
								+ ", bot.codigo, ben.codigo, bot.FECHA_BENEFICIO),'' '') LIKE TO_CHAR(UPPER(''%"
								+ filtro.getValor() + "%''))");
					}
				}
			}
		}
		return retorno.toString();
	}

	private class EmpresaVORowMapper implements RowMapper<EmpresaVO> {

		@Override
		public EmpresaVO mapRow(ResultSet rs, int rowNum) throws SQLException {
			EmpresaVO vo = new EmpresaVO();
			vo.setCodigo(rs.getLong("CODIGO"));
			vo.setTipoDocumento(rs.getString("TIPO_DOCUMENTO"));
			vo.setNitIdupa(rs.getString("NIT_IDUPA"));
			vo.setIdBiometrico(rs.getString("ID_BIOMETRICO"));
			vo.setNombreUpa(rs.getString("NOMBRE_UPA"));
			vo.setRazonSocial(rs.getString("RAZON_SOCIAL"));
			vo.setNomRepLegal(rs.getString("NOM_REP_LEGAL"));
			vo.setDocRepLegal(rs.getString("DOC_REP_LEGAL"));
			vo.setVflCodigoComuna(rs.getLong("VFL_CODIGO_COMUNA"));
			try {
				vo.setStrComuna(rs.getString("STRCOMUNA"));
			} catch (Exception e) {
			}
			vo.setVflCodigoBarrio(rs.getLong("VFL_CODIGO_BARRIO"));
			try {
				vo.setStrBarrio(rs.getString("STRBARRIO"));
			} catch (Exception e) {
			}
			vo.setVflCodigoZona(rs.getLong("VFL_CODIGO_ZONA"));
			try {
				vo.setStrZona(rs.getString("STRZONA"));
			} catch (Exception e) {
			}
			vo.setNombreContacto(rs.getString("NOMBRE_CONTACTO"));
			vo.setDireccion(rs.getString("DIRECCION"));
			vo.setTelefono(rs.getString("TELEFONO"));
			vo.setSector(rs.getString("SECTOR"));
			vo.setSubSector(rs.getString("SUBSECTOR"));
			vo.setNumeroComodato(rs.getString("NUMERO_COMODATO"));
			vo.setEmail(rs.getString("EMAIL"));
			vo.setObservaciones(rs.getString("OBSERVACIONES"));

			return vo;
		}

	}

	private class BeneficioOtorgadoEmpresaVORowMapper implements
			RowMapper<BeneficioOtorgadoEmpresaVO> {
		public BeneficioOtorgadoEmpresaVO mapRow(ResultSet rs, int rowNum)
				throws SQLException {
			BeneficioOtorgadoEmpresaVO vo = new BeneficioOtorgadoEmpresaVO();
			int numColumnas = rs.getMetaData().getColumnCount();

			vo.setValorBeneficio(rs.getLong("valor"));
			vo.setTercero(rs.getString("tercero"));
			vo.setTipoBeneficio(rs.getString("tipo_beneficio"));
			vo.setFechaMedicion(rs.getString("fecha_medicion"));
			vo.getEmpresaVO().setRazonSocial(rs.getString("RAZON_SOCIAL"));
			vo.getEmpresaVO().setNitIdupa(rs.getString("NIT_IDUPA"));
			vo.getEmpresaVO().setVflCodigoComuna(
					rs.getLong("VFL_CODIGO_COMUNA"));
			vo.getEmpresaVO().setVflCodigoBarrio(
					rs.getLong("VFL_CODIGO_BARRIO"));
			vo.getEmpresaVO().setVflCodigoZona(rs.getLong("VFL_CODIGO_ZONA"));
			vo.getEmpresaVO().setDireccion(rs.getString("DIRECCION"));
			vo.getEmpresaVO().setTelefono(rs.getString("TELEFONO"));
			vo.getEmpresaVO().setNomRepLegal(rs.getString("NOM_REP_LEGAL"));
			vo.getEmpresaVO().setDocRepLegal(rs.getString("DOC_REP_LEGAL"));
			vo.setNombrePrograma(rs.getString("NOMBRE_PROGRAMA"));
			vo.setNombreSubprograma(rs.getString("NOMBRE_SUBPROGRAMA"));
			try {
				vo.setVigenciaBeneficio(rs.getString("VIGENCIA_BENEFICIO"));
			} catch (SQLException e) {
			}
			try {
				vo.setPresupTotEjecutado(rs.getLong("PRESUP_TOT_EJECUTADO"));
			} catch (SQLException e) {
			}
			try {
				vo.getEmpresaVO().setTipoDocumento(
						rs.getString("TIPO_DOCUMENTO"));
			} catch (SQLException e) {
			}
			try {
				vo.getEmpresaVO().setNombreUpa(rs.getString("NOMBRE_UPA"));
			} catch (SQLException e) {
			}
			try {
				vo.setNombreSede(rs.getString("SEDE"));
			} catch (SQLException e) {
			}
			try {
				vo.setNombreBarrio(rs.getString("BARRIO"));
			} catch (SQLException e) {
			}
			try {
				vo.setNombreComuna(rs.getString("COMUNA"));
			} catch (SQLException e) {
			}
			try {
				vo.setNombreZona(rs.getString("ZONA"));
			} catch (SQLException e) {
			}
			vo.getEmpresaVO()
					.setNombreContacto(rs.getString("NOMBRE_CONTACTO"));
			vo.getEmpresaVO().setDireccion(rs.getString("DIRECCION"));
			vo.getEmpresaVO().setTelefono(rs.getString("TELEFONO"));
			vo.getEmpresaVO().setSector(rs.getString("SECTOR"));
			vo.getEmpresaVO().setSubSector(rs.getString("SUBSECTOR"));
			vo.getEmpresaVO()
					.setNumeroComodato(rs.getString("NUMERO_COMODATO"));
			vo.getEmpresaVO().setEmail(rs.getString("EMAIL"));
			vo.getEmpresaVO().setObservaciones(rs.getString("OBSERVACIONES"));

			for (int i = 1; i <= numColumnas; i++) {
				String nombreCampo = "CAMPO" + i;
				try {
					String campo = rs.getString(nombreCampo);
					vo.getCampos().add(campo);
					// System.out.println("add " + rs.getString(nombreCampo));
				} catch (SQLException e) {
					// Si el error no es invalid column name, lanzar exception.
					if (e.getErrorCode() != DAOException.INVALID_COLUMN_NAME) {
						throw e;
					}
				}
			}
			return vo;
		}
	}

	/**
	 * HACK..
	 * 
	 * @param filtros
	 * @return Array de Object, primer posicion String a concatenar (ej:
	 *         "AND emp.FECHA_NACIMIENTO >= TO_DATE('01/01/2000')", segunda
	 *         posicion List parametros query, tercera posicion string a
	 *         concatenar subquery, cuarta posicion List parametros subquery.
	 */
	private String buildQueryFiltrosReporteBeneficioOtorgadoDet(
			Collection<CondicionConsultaVO> filtros) {
		StringBuilder retStr = new StringBuilder();

		List<CondicionConsultaVO> lFiltros = (List<CondicionConsultaVO>) filtros;
		CondicionConsultaVO filtro = null;

		if ((Object) filtros != null) {
			for (int i = 0; i < lFiltros.size(); i++) {
				filtro = (CondicionConsultaVO) lFiltros.get(i);
				String operador = filtro.getCodFiltro();
				String tipoDato = filtro.getTipoCampo();

				// Esto se hace por problema de nombre del filtro, conflicto con
				// el tipo_documento de beneficiario. Se cambia aqui a
				// tipo_documento.
				// Si, yo se que es un hack.
				if (filtro.getCodcampo().equals(
						FiltrosReportesUtil.TIPO_DOCUMENTO_EMPRESA)) {
					filtro.setCodcampo(FiltrosReportesUtil.TIPO_DOCUMENTO);
				}

				retStr.append(" AND ");

				if (tipoDato.equals(FiltrosReportesUtil.TIPO_NUMERICO)) {

					if (operador.equals(FiltrosReportesUtil.IGUAL)
							|| operador.equals(FiltrosReportesUtil.DIFERENTE)
							|| operador.equals(FiltrosReportesUtil.MENOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MAYOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MENOR)
							|| operador.equals(FiltrosReportesUtil.MAYOR)) {
						retStr.append(" emp." + filtro.getCodcampo() + " "
								+ operador + " " + filtro.getValor() + " ");

					} else {// BETWEEN
						retStr.append("emp." + filtro.getCodcampo() + " "
								+ operador + " " + filtro.getValor() + " AND "
								+ filtro.getValor2() + " ");
					}

				} else if (tipoDato.equals(FiltrosReportesUtil.TIPO_FECHA)) {

					if (operador.equals(FiltrosReportesUtil.ENTRE)
							|| operador.equals(FiltrosReportesUtil.IGUAL)) {
						retStr.append("emp." + filtro.getCodcampo() + " "
								+ operador + " TO_DATE(" + filtro.getValor()
								+ ", 'dd/mm/rrrr') AND TO_DATE("
								+ filtro.getValor2() + ",'dd/mm/rrrr')");
					} else {
						retStr.append("emp." + filtro.getCodcampo() + " "
								+ operador + " TO_DATE(" + filtro.getValor()
								+ ", 'dd/mm/rrrr')");
					}

				} else if (tipoDato
						.equals(FiltrosReportesUtil.TIPO_ALFANUMERICO)
						|| tipoDato.equals("L")) {
					if (operador.equals(FiltrosReportesUtil.IGUAL)
							|| operador.equals(FiltrosReportesUtil.DIFERENTE)) {
						retStr.append(" UPPER(emp." + filtro.getCodcampo()
								+ " ) " + operador + " '"
								+ filtro.getValor().toUpperCase() + "' ");

					} else if (operador.equals(FiltrosReportesUtil.PARECIDO)) {
						retStr.append(" UPPER(emp." + filtro.getCodcampo()
								+ " ) " + FiltrosReportesUtil.PARECIDO + " "
								+ "'%" + filtro.getValor().toUpperCase() + "%'"
								+ " ");
					}
				} else {
					if (operador.equals(FiltrosReportesUtil.IGUAL)
							|| operador.equals(FiltrosReportesUtil.DIFERENTE)
							|| operador.equals(FiltrosReportesUtil.MENOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MAYOR_IGUAL)
							|| operador.equals(FiltrosReportesUtil.MENOR)
							|| operador.equals(FiltrosReportesUtil.MAYOR)) {
						retStr.append(" emp." + filtro.getCodcampo() + " "
								+ operador + " '" + filtro.getValor() + "' ");
					} else { // BETWEEN
						retStr.append("emp." + filtro.getCodcampo() + " "
								+ operador + " " + filtro.getValor() + " AND "
								+ filtro.getValor2() + " ");
					}

				}

			}
		}
		return retStr.toString();
	}

}
